package com.czk.originfeign.register;

import com.czk.originfeign.annotation.FeignApi;
import feign.Feign;
import feign.Request;
import feign.Retryer;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * 扫描注册带有@FeignApi的对象
 *
 * @Author:ChenZhangKun
 * @Date: 2021/8/10 17:47
 */
@Component
public class FeignClientRegister implements BeanFactoryPostProcessor {
    private static final String scanPath = "com.czk.originfeign";

    /**
     * BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后，
     * 在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory，使用该参数，可以获取到相关bean的定义信息
     * @param configurableListableBeanFactory
     * @throws BeansException
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        // 拿到所有标注了feign class的类
        List<String> classes = scan(scanPath);
        if (classes == null) {
            return;
        }
        System.out.println(classes);
        Feign.Builder builder = getFeignBuilder();
        // 遍历
        for (String clazz : classes) {
            Class<?> targetClass = null;
            try {
                // 反射
                targetClass = Class.forName(clazz);
                // 拿到注解
                FeignApi feignApi = targetClass.getAnnotation(FeignApi.class);
                // 拿到地址
                String url = feignApi.serviceUrl();
                //
                if (url.indexOf("http://") != 0) {
                    url = "http://" + url;
                }
                // 构建对象
                Object target = builder.target(targetClass, url);
                // 住进工厂
                configurableListableBeanFactory.registerSingleton(targetClass.getName(), target);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 配feign客户端
     *
     * @return
     */
    private Feign.Builder getFeignBuilder() {
        Feign.Builder builder = Feign.builder()
                .encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder())
                .options(new Request.Options(1000, 3500))
                .retryer(new Retryer.Default(5000, 5000, 3));
        return builder;
    }

    List<String> result = new ArrayList<>();

    private List<String> scan(String scanPath) {
        // 扫描路径·
        URL resource = FeignClientRegister.class.getClassLoader().getResource(scanPath.replaceAll("\\.", "/"));
        // 拿到文件地址
        String fileStr = resource.getFile();
        // 转为文件
        File file = new File(fileStr);
        // 拿到全部文件
        String[] list = file.list();
        // 遍历
        for (String s : list) {
            // 转为文件
            File file1 = new File(fileStr + "/" + s);
            // 是否是文件
            if (file1.isDirectory()) {
                scan(scanPath + "." + s);
            } else {
                // 拿到字节码
                try {
                    Class<?> clazz = Class.forName((scanPath + "." + s).replaceAll(".class", ""));
                    // 是否被路径标记
                    if (clazz.isAnnotationPresent(FeignApi.class)) {
                        result.add((scanPath + "." + s).replaceAll(".class", ""));
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
}
